package com.bocloud.cmp.service.resource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.AlarmDao;
import com.bocloud.cmp.dao.BucketDao;
import com.bocloud.cmp.dao.CloudServerDao;
import com.bocloud.cmp.dao.CloudVendorDao;
import com.bocloud.cmp.dao.ClusterDao;
import com.bocloud.cmp.dao.DataStoreDao;
import com.bocloud.cmp.dao.FlavorDao;
import com.bocloud.cmp.dao.HostSystemDao;
import com.bocloud.cmp.dao.ImageDao;
import com.bocloud.cmp.dao.NetworkCardDao;
import com.bocloud.cmp.dao.NetworkDao;
import com.bocloud.cmp.dao.NetworkHostDao;
import com.bocloud.cmp.dao.PortDao;
import com.bocloud.cmp.dao.PortGroupDao;
import com.bocloud.cmp.dao.RouteDao;
import com.bocloud.cmp.dao.SecurityGroupDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.dao.StoreHostDao;
import com.bocloud.cmp.dao.SubnetDao;
import com.bocloud.cmp.dao.VdcDao;
import com.bocloud.cmp.dao.VolumeDao;
import com.bocloud.cmp.driver.providers.intf.AlarmProvider;
import com.bocloud.cmp.driver.providers.intf.AuthProvider;
import com.bocloud.cmp.entity.resource.Alarm;
import com.bocloud.cmp.entity.resource.CloudVendor;
import com.bocloud.cmp.entity.resource.HostSystem;
import com.bocloud.cmp.enums.VendorType;
import com.bocloud.cmp.interfaces.resource.CloudVendorService;
import com.bocloud.cmp.interfaces.resource.SyncService;
import com.bocloud.cmp.model.CloudVendorBean;
import com.bocloud.cmp.service.utils.RegisterVendor;
import com.bocloud.common.enums.BaseStatus;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.KeyGenerator;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.config.client.ZkClientHelper;
import com.bocloud.coordinator.esb.intf.EsbService;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.google.common.collect.Lists;

/**
 * CloudVendor Service实现类
 * 
 * @author dongkai
 *
 */
@Service("cloudVendorService")
public class CloudVendorServiceImpl implements CloudVendorService {

	private Logger logger = LoggerFactory.getLogger(CloudVendorServiceImpl.class);
	@Autowired
	private CloudVendorDao cloudVendorDao;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private CloudServerDao cloudServerDao;
	@Autowired
	private EsbService esbService;
	@Autowired
	private ZkClientHelper zkClientHelper;
	@Autowired
	private ImageDao imageDao;
	@Autowired
	private SnapshotDao snapshotDao;
	@Autowired
	private FlavorDao flavorDao;
	@Autowired
	private NetworkDao networkDao;
	@Autowired
	private BucketDao bucketDao;
	@Autowired
	private SubnetDao subnetDao;
	@Autowired
	private SecurityGroupDao securityGroupDao;
	@Autowired
	private VdcDao vdcDao;
	@Autowired
	private ClusterDao clusterDao;
	@Autowired
	private HostSystemDao hostSystemDao;
	@Autowired
	private DataStoreDao dataStoreDao;
	@Autowired
	private StoreHostDao storeHostDao;
	@Autowired
	private AlarmDao alarmDao;
	@Autowired
	private NetworkCardDao networkCardDao;
	@Autowired
	private AuthProvider authProvider;
	@Autowired
	private AlarmProvider alarmProvider;
	@Autowired
	private VolumeDao volumeDao;
	@Autowired
	private PortDao portDao;
	@Autowired
	private RouteDao routeDao;
	@Autowired
	private NetworkHostDao networkHostDao;
	@Autowired
	private PortGroupDao portGroupDao;
	@Autowired
	private SyncService syncService;

	@Transactional
	@Override
	public BsmResult create(CloudVendor cloudVendor) {
		try {
			// 添加
			// 先进行同名认证，虽然输入时已验证，可能浏览器会记录信息
			CloudVendor cloudQuery = cloudVendorDao.getByName(cloudVendor.getName());
			if (null != cloudQuery) {
				return new BsmResult(false, "添加失败，名称重复");
			}
			// 正则获取IP
			String address = cloudVendor.getAddress();
			String regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
			Pattern p = Pattern.compile(regex);
			Matcher m = p.matcher(address);
			if (m.find()) {
				address = m.group();
			}
			cloudQuery = cloudVendorDao.getByAddress(address);
			if (null != cloudQuery) {
				return new BsmResult(false, "此平台已存在，不能重复添加!");
			}
			cloudVendor.setStatus(BaseStatus.NORMAL.name());
			cloudVendor.setUuid(KeyGenerator.uuid());
			// 在zk注册信息
			List<CloudVendor> list = cloudVendorDao.listAll();
			list.add(cloudVendor);
			RegisterVendor.register(esbService, zkClientHelper, list);
			// 认证
			BsmResult result = authProvider.auth(cloudVendor.getUuid(), "");
			if (!result.isSuccess()) {
				return new BsmResult(false, result.getMessage());
			}
			cloudVendorDao.save(cloudVendor);
			VendorType vendorType = VendorType.valueOf(cloudVendor.getType());
			syncService.sync(cloudVendor.getId(), null, cloudVendor.getCreaterId());
			this.syncAlarm(cloudVendor.getId(), cloudVendor.getCreaterId(), cloudVendor.getUuid(), vendorType);
			return new BsmResult(true, cloudVendor.getId(), "添加成功");
		} catch (Exception e) {
			logger.error("create cloudVendor fail:", e);
			return new BsmResult(false, "添加失败");
		}
	}

	/**
	 * 同步
	 * 
	 * @param params
	 * @param cloudVendor
	 * @param vendorType
	 * @param regions
	 */
	private void syncAlarm(Long vendorId, Long userId, String uuid, VendorType type) {
		// 启动一个线程从MQ上获取数据
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					BsmResult bsmResult = alarmProvider.list(uuid, null);
					if (bsmResult.isSuccess() && null != bsmResult.getData()) {
						String content = JSONObject.toJSONString(bsmResult.getData());
						switch (type) {
						case OPENSTACK:
							break;
						case VMWARE:
							List<Alarm> alarms = JSONObject.parseArray(content, Alarm.class);
							for (Alarm alarm : alarms) {
								alarm.setCreaterId(userId);
								alarm.setMenderId(userId);
								alarm.setVendorId(vendorId);
								if (null == alarm.getConfirmer()) {
									alarm.setStatus("UNCONFIRM");
								} else {
									alarm.setStatus("CONFIRMED");
								}
								if (alarm.getLevel().equals("red")) {
									alarm.setLevel("DANGER");
								} else {
									alarm.setLevel("WARN");
								}
								alarmDao.save(alarm);
							}
							break;
						default:
							break;
						}
					}
				} catch (Exception e) {
					logger.error("Get Message Exception:", e);
				}
			}
		}).start();
	}

	@Transactional
	@Override
	public BsmResult modify(CloudVendorBean bean, Long userId) {
		String path = CloudVendor.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			CloudVendor cloudVendor = cloudVendorDao.query(bean.getId());
			if (null == cloudVendor) {
				logger.warn("cloudVendor data not exist");
				return new BsmResult(false, "数据不存在");
			}
			if (!bean.getName().equals(cloudVendor.getName())) {
				CloudVendor vendor = cloudVendorDao.getByName(bean.getName());
				if (null != vendor) {
					return new BsmResult(false, "名称不能重复!");
				}
			}
			BeanUtils.copyProperties(bean, cloudVendor);
			cloudVendor.setMenderId(userId);
			Boolean result = cloudVendorDao.update(cloudVendor);
			return result ? new BsmResult(true, "修改成功") : new BsmResult(false, "修改失败");
		} catch (Exception e) {
			logger.error("modify cloudVendor fail:", e);
			return new BsmResult(false, "修改失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Transactional
	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = CloudVendor.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		boolean result = false;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			CloudVendor cloudVendor = cloudVendorDao.query(id);
			if (null == cloudVendor) {
				logger.warn("cloudVendor data not exist");
				return new BsmResult(false, "数据不存在");
			}
			VendorType type = VendorType.valueOf(cloudVendor.getType());
			// 删除虚拟机
			cloudServerDao.removeByVid(id, userId);
			switch (type) {
			case OPENSTACK:
				imageDao.removeByVid(id, userId);
				volumeDao.removeByVid(id, userId);
				snapshotDao.removeByVid(id, userId);
				flavorDao.removeByVid(id);
				portDao.removeByVid(id);
				subnetDao.removeByVid(id);
				networkDao.removeByVid(id, userId);
				routeDao.removeByVid(id);
				alarmDao.removeByVid(id, userId);
				hostSystemDao.removeByVendor(id, userId);
				break;
			case ALIYUN:
				imageDao.removeByVid(id, userId);
				volumeDao.removeByVid(id, userId);
				securityGroupDao.removeByVid(id);
				bucketDao.removeByVid(id, userId);
				// zoneDao.removeByVid(id);
				break;
			case VMWARE:
				vdcDao.removeByVendor(id, userId);
				clusterDao.removeByVendor(id, userId);
				hostSystemDao.removeByVendor(id, userId);
				dataStoreDao.removeByVendor(id, userId);
				storeHostDao.removeByVendor(id);
				snapshotDao.removeByVid(id, userId);
				networkDao.removeByVid(id, userId);
				networkCardDao.removeByVid(id, userId);
				alarmDao.removeByVid(id, userId);
				networkHostDao.removeByVendor(id);
				portGroupDao.removeByVid(id, userId);
				break;
			case JDYUN:
				break;
			default:
				break;
			}
			result = cloudVendorDao.delete(id, userId);
			// 在zk注册信息
			List<CloudVendor> cloudVendors = cloudVendorDao.listAll();
			RegisterVendor.register(esbService, zkClientHelper, cloudVendors);
		} catch (Exception e) {
			logger.error("remove cloudVendor fail:", e);
			return new BsmResult(false, "删除失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
		return result ? new BsmResult(true, "删除成功") : new BsmResult(false, "删除失败");
	}

	@Transactional
	@Override
	public BsmResult lock(Long id, Long userId) {
		String path = CloudVendor.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		boolean result = false;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			CloudVendor cloudVendor = cloudVendorDao.query(id);
			if (null == cloudVendor) {
				logger.warn("cloudVendor data not exist");
				return new BsmResult(false, "数据不存在");
			}
			result = cloudVendorDao.lock(id, userId);
		} catch (Exception e) {
			logger.error("freeze cloudVendor fail:", e);
			return new BsmResult(false, "冻结失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
		return result ? new BsmResult(true, "冻结成功") : new BsmResult(false, "冻结失败");
	}

	@Transactional
	@Override
	public BsmResult active(Long id, Long userId) {
		String path = CloudVendor.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		boolean result = false;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			CloudVendor cloudVendor = cloudVendorDao.query(id);
			if (null == cloudVendor) {
				logger.warn("cloudVendor data not exist");
				return new BsmResult(false, "数据不存在");
			}
			result = cloudVendorDao.active(id, userId);
		} catch (Exception e) {
			logger.error("freeze cloudVendor fail:", e);
			return new BsmResult(false, "激活失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
		return result ? new BsmResult(true, "激活成功") : new BsmResult(false, "激活失败");
	}

	@Override
	public BsmResult detail(Long id) {
		try {
			CloudVendor cloudVendor = cloudVendorDao.query(id);
			// 统计数量
			int instance = 0;
			int online = 0;
			int template = 0;
			List<Param> paramMap = Lists.newArrayList();
			Long vendorId = cloudVendor.getId();
			Map<String, Object> map = MapTools.simpleMap("status", "RUNNING");
			map.put("vendorId", vendorId);
			paramMap.add(new Param(map, Sign.EQ));
			// 虚拟机数量
			instance = cloudServerDao.listByVid(vendorId).size();
			online = cloudServerDao.count(paramMap);
			cloudVendor.setInstance(instance);
			cloudVendor.setOnline(online);
			cloudVendor.setOffline(instance - online);
			// 模板数量
			paramMap.clear();
			map = MapTools.simpleMap("vendorId", vendorId);
			if (cloudVendor.getType().equals(VendorType.OPENSTACK.name())) {
				paramMap.add(new Param(map, Sign.EQ));
				template = flavorDao.count(paramMap);
			} else {
				map.put("isTemplate", 1);
				paramMap.add(new Param(map, Sign.EQ));
				template = cloudServerDao.count(paramMap);
			}
			cloudVendor.setTemplateCount(template);
			// 主机数量
			paramMap.clear();
			paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
			int host = hostSystemDao.count(paramMap);
			cloudVendor.setHostCount(host);
			if (cloudVendor.getType().equals(VendorType.VMWARE.name())) {
				// 存储数量
				paramMap.clear();
				paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
				cloudVendor.setDataStoreCount(dataStoreDao.count(paramMap));
				// 集群数量
				paramMap.clear();
				paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
				cloudVendor.setClusterCount(clusterDao.count(paramMap));
			} else if (cloudVendor.getType().equals(VendorType.OPENSTACK.name())) {
				// 存储数量
				paramMap.clear();
				paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
				cloudVendor.setDataStoreCount(volumeDao.count(paramMap));
				// 镜像数量
				paramMap.clear();
				paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
				cloudVendor.setImageCount(imageDao.count(paramMap));
			}
			List<HostSystem> hosts = hostSystemDao.listByVendor(id);
			int cpuTotal = 0;
			int memTotal = 0;
			int cpuCount = 0;
			for (HostSystem hostSystem : hosts) {
				cpuTotal += hostSystem.getCpuTotal();
				memTotal += hostSystem.getMemTotal();
				cpuCount += hostSystem.getCpuCore();
			}
			cloudVendor.setCpuTotal(cpuTotal);
			cloudVendor.setMemTotal(memTotal);
			cloudVendor.setCpuCount(cpuCount);
			return new BsmResult(true, cloudVendor, "查询详情成功");
		} catch (Exception e) {
			logger.error("query cloudVendor detail fail:", e);
			return new BsmResult(false, "查询详情失败");
		}
	}

	@Override
	public BsmResult checkName(String name) {
		try {
			CloudVendor cloudVendor = cloudVendorDao.getByName(name);
			if (null == cloudVendor) {
				return new BsmResult(true, "检查名称成功！");
			} else {
				return new BsmResult(false, "检查名称重复!");
			}
		} catch (Exception e) {
			logger.error("get cloudVendor by name fail", e);
			return new BsmResult(false, "检查名称失败!");
		}
	}

	@Override
	public BsmResult list(Integer page, Integer rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		List<CloudVendor> list = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			if (null == params) {
				params = new ArrayList<>();
			}
			total = cloudVendorDao.count(params);
			if (simple) {
				beans = this.cloudVendorDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = cloudVendorDao.list(page, rows, params, sorter);
				int instance = 0;
				int online = 0;
				int template = 0;
				for (CloudVendor cloudVendor : list) {
					Long vendorId = cloudVendor.getId();
					// 统计数量
					List<Param> paramMap = Lists.newArrayList();
					Map<String, Object> map = MapTools.simpleMap("status", "RUNNING");
					map.put("vendorId", vendorId);
					paramMap.add(new Param(map, Sign.EQ));
					// 虚拟机数量
					instance = cloudServerDao.listByVid(vendorId).size();
					online = cloudServerDao.count(paramMap);
					cloudVendor.setInstance(instance);
					cloudVendor.setOnline(online);
					cloudVendor.setOffline(instance - online);
					// 模板数量
					paramMap.clear();
					map = MapTools.simpleMap("vendorId", vendorId);
					if (cloudVendor.getType().equals(VendorType.OPENSTACK.name())) {
						paramMap.add(new Param(map, Sign.EQ));
						template = flavorDao.count(paramMap);
					} else {
						map.put("isTemplate", 1);
						paramMap.add(new Param(map, Sign.EQ));
						template = cloudServerDao.count(paramMap);
					}
					cloudVendor.setTemplateCount(template);
					// 主机数量
					paramMap.clear();
					paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
					int host = hostSystemDao.count(paramMap);
					cloudVendor.setHostCount(host);
					if (cloudVendor.getType().equals(VendorType.VMWARE.name())) {
						// 存储数量
						paramMap.clear();
						paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
						cloudVendor.setDataStoreCount(dataStoreDao.count(paramMap));
						// 集群数量
						paramMap.clear();
						paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
						cloudVendor.setClusterCount(clusterDao.count(paramMap));
					} else if (cloudVendor.getType().equals(VendorType.OPENSTACK.name())) {
						// 存储数量
						paramMap.clear();
						paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
						cloudVendor.setDataStoreCount(volumeDao.count(paramMap));
						// 镜像数量
						paramMap.clear();
						paramMap.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
						cloudVendor.setImageCount(imageDao.count(paramMap));
					}

					List<HostSystem> hosts = hostSystemDao.listByVendor(vendorId);
					int cpuTotal = 0;
					int memTotal = 0;
					int cpuCount = 0;
					for (HostSystem hostSystem : hosts) {
						cpuTotal += hostSystem.getCpuTotal();
						memTotal += hostSystem.getMemTotal();
						cpuCount += hostSystem.getCpuCore();
					}
					cloudVendor.setCpuTotal(cpuTotal);
					cloudVendor.setMemTotal(memTotal);
					cloudVendor.setCpuCount(cpuCount);
				}
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
		} catch (Exception e) {
			logger.error("list cloudVendor fail:", e);
			return new BsmResult(false, "查询失败");
		}
		return new BsmResult(true, gridBean, "查询成功");
	}

	@Override
	public List<CloudVendor> list(String type) {
		try {
			List<Param> params = Lists.newArrayList();
			params.add(new Param(MapTools.simpleMap("type", type), Sign.EQ));
			return cloudVendorDao.list(1, Integer.MAX_VALUE, params, null);
		} catch (Exception e) {
			logger.error("list cloudVendor fail:", e);
			return Lists.newArrayList();
		}
	}

	@Override
	public List<CloudVendor> listAll() {
		try {
			return cloudVendorDao.listAll();
		} catch (Exception e) {
			logger.error("list cloudVendor fail:", e);
			return Lists.newArrayList();
		}
	}

}
